---
type: tutorial
title: 첫 번째 스크립트를 브라우저로 보내기
description: >-
  튜토리얼: 첫 번째 Astro 블로그 구축 — Astro 스크립트 태그를 사용하여 모바일 탐색에 클라이언트 측 상호 작용 기능 추가
i18nReady: true
---
import Blanks from '~/components/tutorial/Blanks.astro';
import Box from '~/components/tutorial/Box.astro';
import Checklist from '~/components/Checklist.astro';
import MultipleChoice from '~/components/tutorial/MultipleChoice.astro';
import Option from '~/components/tutorial/Option.astro';
import PreCheck from '~/components/tutorial/PreCheck.astro';
import { Steps } from '@astrojs/starlight/components';

클라이언트 측 상호 작용이 필요한 모바일 화면 크기에서 탐색 메뉴를 열고 닫을 수 있는 버튼을 추가해 보겠습니다.

<PreCheck>
  - 메뉴 컴포넌트 만들기
  - 사이트 방문자가 탐색 메뉴를 열고 닫을 수 있도록 `<script>` 작성
  - JavaScript를 `.js` 파일로 이동
</PreCheck>

## 메뉴 컴포넌트 구축

모바일 메뉴를 열고 닫을 수 있는 `<Menu />` 컴포넌트를 만듭니다.

<Steps>
1. `src/components/`에 `Menu.astro`라는 파일을 생성합니다.
  
2. 다음 코드를 컴포넌트에 복사합니다. 이는 모바일 기기에서 탐색 링크의 표시 여부를 전환하는 데 사용될 버튼을 생성합니다. (나중에 `global.css`에 새 CSS 스타일을 추가할 것입니다.)

    ```astro title="src/components/Menu.astro"
    --- 
    ---
    <button aria-expanded="false" aria-controls="main-menu" class="menu">
      Menu
    </button>
    ```

3. 이 새로운 `<Menu />` 컴포넌트를 `Header.astro`의 `<Navigation />` 컴포넌트 바로 앞에 배치하세요.

    <details>
    <summary>코드를 확인하세요!</summary>

    ```astro title="src/components/Header.astro" ins={2,7}
    ---
    import Menu from './Menu.astro';
    import Navigation from './Navigation.astro';
    ---
    <header>
      <nav>
        <Menu />
        <Navigation />
      </nav>
    </header>
    ```
    </details>

4. 메뉴 컴포넌트에 다음 스타일을 추가하세요. 여기에는 반응형 스타일도 포함됩니다.

    ```css title="src/styles/global.css" ins={2-9, 33-35, 51-53}
    /* nav 스타일 */
    .menu {
      background-color: #0d0950;
      border: none;
      color: #fff;
      font-size: 1.2rem;
      font-weight: bold;
      padding: 5px 10px;
    }

    .nav-links {
      width: 100%;
      display: none;
      margin: 0;
    }

    .nav-links a {
      display: block;
      text-align: center;
      padding: 10px 0;
      text-decoration: none;
      font-size: 1.2rem;
      font-weight: bold;
      text-transform: uppercase;
      color: #0d0950;
    }
    
    .nav-links a:hover,
    .nav-links a:focus {
      background-color: #ff9776;
    }

    :has(.menu[aria-expanded="true"]) .nav-links {
      display: unset;
    }

    @media screen and (min-width: 636px) {
      .nav-links {
        margin-left: 5em;
        display: block;
        position: static;
        width: auto;
        background: none;
      }

      .nav-links a {
        display: inline-block;
        padding: 15px 20px;
      }

      .menu {
        display: none;
      }
    }
    ```
</Steps>

## 첫 번째 스크립트 태그 작성

탐색 링크를 표시하거나 숨기기 위해 메뉴를 클릭하는 등의 사용자 입력에 응답할 수 없기 때문에 헤더는 아직 **대화형**이 아닙니다.

`<script>` 태그를 추가하면 클라이언트 측 JavaScript가 사용자 이벤트를 '수신'한 후 그에 따라 응답합니다.

<Steps>
1. Astro의 TypeScript 지원을 활용하여, `index.astro`의 닫는 `</body>` 태그 바로 앞에 다음 `<script>` 태그를 추가합니다.

    ```astro title="src/pages/index.astro" ins={2-9}
      <Footer />
      <script>
        const menu = document.querySelector('.menu');
  
        menu?.addEventListener('click', () => {
          const isExpanded = menu.getAttribute('aria-expanded') === 'true';
          menu.setAttribute('aria-expanded', `${!isExpanded}`);
        });
      </script>
    </body>
    ```

2. 다양한 크기의 브라우저 미리보기를 다시 확인하고, 화면 크기와 이 페이지의 사용자 입력에 반응하는 탐색 메뉴가 작동하는지 확인하세요.
</Steps>

### `.js` 파일 가져오기

각 페이지에 JavaScript를 직접 작성하는 대신 `<script>` 태그의 내용을 프로젝트의 자체 `.js` 파일로 이동할 수 있습니다.

<Steps>
1. `src/scripts/menu.js`를 생성하고 (새 `/scripts/` 폴더를 생성해야 함) JavaScript를 해당 폴더로 이동합니다.

    ```js title="src/scripts/menu.js"
    const menu = document.querySelector('.menu');

    menu?.addEventListener('click', () => {
      const isExpanded = menu.getAttribute('aria-expanded') === 'true';
      menu.setAttribute('aria-expanded', `${!isExpanded}`);
    });
    ```

2. `index.astro`의 `<script>` 태그 내용을 다음 파일 가져오기로 바꿉니다.

    ```astro title="src/pages/index.astro" ins={7} del={3-8}
      <Footer />
      <script>
        const menu = document.querySelector('.menu');
  
        menu?.addEventListener('click', () => {
          const isExpanded = menu.getAttribute('aria-expanded') === 'true';
          menu.setAttribute('aria-expanded', `${!isExpanded}`);
        });

        import "../scripts/menu.js";
      </script>
    </body>
    ```

3. 더 작은 크기로 브라우저 미리보기를 다시 확인하고 메뉴가 여전히 탐색 링크를 열고 닫는지 확인하세요.

4. 가져오기와 동일한 `<script>`를 다른 두 페이지인 `about.astro` 및 `blog.astro`에 추가하고 각 페이지에 반응형 대화형 헤더가 있는지 확인하세요.

    ```astro title="src/pages/about.astro & src/pages/blog.astro" ins={2-4}
      <Footer />
      <script>
        import "../scripts/menu.js";
      </script>
    </body>
    ```
</Steps>

:::note[핵심사항]
이전에 일부 JavaScript를 사용하여 사이트의 일부를 구축했습니다.

- 페이지 제목들을 (title, heading) 동적으로 정의
- 정보 페이지의 기술 목록을 통한 매핑
- HTML 요소를 조건부로 표시

이러한 명령은 모두 빌드 시 실행되어 사이트에 대한 정적 HTML을 생성한 다음 코드가 "버려집니다."

**`<script>` 태그의 JavaScript는 브라우저로 전송되며**, 페이지 새로 고침 또는 입력 토글과 같은 사용자 상호 작용을 기반으로 실행할 수 있습니다.
:::

<Box icon="question-mark">

### 지식을 테스트해보세요

1. Astro는 언제 컴포넌트의 프런트매터에 작성된 JavaScript를 실행합니까?

    <MultipleChoice>
      <Option>
       Astro는 절대로 JavaScript를 실행하지 않습니다.
      </Option>
      <Option isCorrect>
        빌드 타임에
      </Option>
      <Option>
         방문자가 버튼을 클릭할 때
      </Option>
    </MultipleChoice>

2. 선택적으로 Astro는 브라우저에 JavaScript를 보내 다음을 허용할 수 있습니다.

    <MultipleChoice>
      <Option>
        사용자가 페이지를 클릭
      </Option>
      <Option>
        더 빠른 로드 시간
      </Option>
      <Option isCorrect>
        클라이언트 측 상호작용
      </Option>
    </MultipleChoice>

3. 클라이언트 측 JavaScript는 어디에서 작성되거나 가져올 때 사용자의 브라우저로 전송되나요?

    <MultipleChoice>
      <Option isCorrect>
        `<script>` 태그
      </Option>
      <Option>
        `.astro` 파일의 코드 펜스
      </Option>
      <Option>
        `global.css`
      </Option>
    </MultipleChoice>

</Box>

<Box icon="check-list">

## 체크리스트

<Checklist>
- [ ] `<script>` 태그에 JavaScript를 사용하여 클라이언트 측 상호 작용을 추가할 수 있습니다.
- [ ] `.js` 파일을 `<script>` 태그로 가져올 수 있습니다.
</Checklist>

</Box>

### 참고 자료

[Astro의 클라이언트 측 스크립트](/ko/guides/client-side-scripts/)
